package com.yst.webplugin.util;

import com.yst.web.utils.ClassUtils;
import com.yst.web.utils.JsonConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class ReqParamsUtils {

    public static final String RequestJSON="application/json";

    public static final String RequestForm="multipart/form-data";

    public static final String RequestFormJsonKey="data";
    /**
     * fetch json from request
     * @param request http request
     * @return json text
     */
    public static String getJsonString(HttpServletRequest request)  {
        if (StringUtils.compareIgnoreCase(request.getMethod(),"get")==1) return "";
        if (Objects.nonNull(request.getContentType())&&request.getContentType().startsWith(RequestJSON)){
            try(BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(request.getInputStream()))) {
                String line = "";
                StringBuilder stringBuilder = new StringBuilder();
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line);
                }
                return stringBuilder.toString();
            }
            catch (Exception exception){
                 exception.printStackTrace();
            }
        }
        if (Objects.nonNull(request.getContentType())&&request.getContentType().startsWith(RequestForm)){
            return getFormDataAsJson(request);
        }
        return null;
    }

    /**
     * determine string is an array
     * @param jsonString json string
     * @return true is an array,false is not an array
     */
    public static boolean isArray(String jsonString){
        if (Objects.nonNull(jsonString)) {
            return jsonString.startsWith("[") && jsonString.endsWith("]");
        }
        else
        {
            return false;
        }
    }
    /**
     * determine string is an array
     * @param request http request
     * @return true is an array,false is not an array
     */
    public static boolean isArray(HttpServletRequest request) {
        try {
            String json = getJsonString(request);
            return json.startsWith("[") && json.endsWith("]");
        }
        catch (Exception e){
            return false;
        }
    }

    /**
     * determine a string is a json object string
     * @param jsonString json string
     * @return true is an object,false is not an object
     */
    public static boolean isObject(String jsonString){
        return jsonString.startsWith("{")&&jsonString.endsWith("}");
    }

    /**
     * fetch body of request as an object
     * @param request http request
     * @param clazz class of target
     * @param <T> T
     * @return object
     */
    public static <T> T getJsonObject(HttpServletRequest request,Class<T> clazz) {
        String jsonString=getJsonString(request);
        return JsonConverter.getJsonConverter().parseObject(jsonString,clazz);
    }

    /**
     * fetch object from request by class use json
     * @param request http request
     * @param clazz class
     * @param <T> T
     * @return data of form
     */
    public static <T> T getFormData(HttpServletRequest request,Class<T> clazz) {
        if (request.getContentType().startsWith(RequestForm)){
            String strJson=getFormDataAsJson(request);
            return JsonConverter.getJsonConverter().parseObject(strJson,clazz);
        }
        return null;
    }

    /**
     * fetch form value as json string
     * @param request http request
     * @return json string
     */
    public static String getFormDataAsJson(HttpServletRequest request,String formJsonKey){
        if (request.getParameterMap().containsKey(formJsonKey)) {
            return request.getParameterMap().get(formJsonKey)[0];
        }
        Map<String,Object> body=new HashMap<>();
        request.getParameterMap().forEach((key,value)->{
            if (value.length>1) {
                body.put(key, Arrays.asList(value));
            }
            else {
                body.put(key,value[0]);
            }
        });
        return JsonConverter.getJsonConverter().toJSONString(body);
    }

    /**
     * fetch json from form of request by "data"
     * @param request http request
     * @return json string
     */
    public static String getFormDataAsJson(HttpServletRequest request){
        return getFormDataAsJson(request,RequestFormJsonKey);
    }

    public static <T> T getParamObject(String requestJsonBody,Class<T> clazz) {
        try {
            T data = JsonConverter.getJsonConverter().parseObject(requestJsonBody, clazz);
            if (Objects.nonNull(data)) {
                return data;
            }
        }
        catch (Exception e){
            log.error(e.getMessage(),e);
        }
        return null;
    }

    /**
     * fetch body of request as list by specific class of element
     * @param request http request
     * @param elementClazz class of element
     * @param <T> T
     * @return list of specific class
     */
    public static <T> List<T> getParamAsList(HttpServletRequest request, Class<T> elementClazz) {
        return JsonConverter.getJsonConverter().parseList(getJsonString(request),elementClazz);
    }

    /**
     * convert string to array of T
     * @param jsonString source json string
     * @param elementClazz class of target
     * @param <T> T
     * @return List of T
     */
    public static <T> List<T> getParamAsList(String jsonString, Class<T> elementClazz)  {
        return JsonConverter.getJsonConverter().parseList(jsonString,elementClazz);
    }


    /**
     * fetch parameter
     * @param params map of parameter
     * @param paramName name of parameter
     * @param defaultValue default value
     * @return if there is value,return the value,otherwise,return default value
     * @param <T> T
     */
    public static <T> T getParam(Map<String,Object> params,String paramName,T defaultValue){
        if (params.containsKey(paramName)){
            Class<?> valueClass= defaultValue.getClass();
            if (params.get(paramName).getClass()==valueClass){
                return (T)params.get(paramName);
            }
            if (ClassUtils.isPrimitive(valueClass)&&ClassUtils.haveStaticMethod(valueClass,"valueOf"))
            {
                Optional<Method> method= ClassUtils.getMethods(defaultValue.getClass(),"valueOf")
                        .stream().filter((m)-> Modifier.isStatic(m.getModifiers())).collect(Collectors.toList()).stream().findFirst();
                if (method.isPresent()){
                    try {
                        return (T)(method.get().invoke(null, defaultValue));
                    }
                    catch (Exception e){
                        //ignore error
                    }
                }
            }

            String valueString;
            if (params.get(paramName) instanceof String){
                valueString=(String)params.get(paramName);
            }
            else {
                valueString=JsonConverter.getJsonConverter().toJSONString(params.get(paramName));
            }
            return JsonConverter.getJsonConverter().parseObject(valueString,
                    (Class<? extends T>) valueClass);

        }
        else {
            return defaultValue;
        }
    }

}
